<?php
/**
 * Created by PhpStorm.
 * User: 1
 * Date: 2017-07-10
 * Time: 15:04
 */

namespace app\index\command;


use app\index\helper\CommandHelper;
use app\src\base\helper\ValidateHelper;
use app\src\sunsun\common\logic\UserDeviceLogic;
use app\src\sunsun\heatingRod\action\HeatingRodDeviceEventAction;
use app\src\sunsun\heatingRod\action\HeatingRodTcpLogAction;
use app\src\sunsun\heatingRod\action\HeatingRodTempHisAction;
use app\src\sunsun\heatingRod\logic\HeatingRodDeviceEventLogic;
use app\src\sunsun\heatingRod\logic\HeatingRodDeviceLogic;
use app\src\sunsun\heatingRod\model\HeatingRodDeviceEvent;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;

class HeatingRodCommand extends Command
{
    protected function initialize(Input $input, Output $output)
    {
        CommandHelper::loadLang(['zh-cn', 'en', 'zh-tw']);
    }

    protected function configure()
    {
        $this->setName('device:heating_rod')
            ->addOption('interval', '', Option::VALUE_OPTIONAL, 'device event process sleep {interval} seconds', 30)
            ->addOption('size', '', Option::VALUE_OPTIONAL, 'device event process sizes per time', 10)
            ->addOption('type', '', Option::VALUE_OPTIONAL, 'command type, support (process_event,offline,clear)', 'clear')
            ->setDescription('heating_rod device event process');
    }

    protected function execute(Input $input, Output $output)
    {
        $time = microtime(true);
        $size = $input->getOption('size');
        $type = $input->getOption('type');
        $interval = $input->getOption('interval');
        $output->info('type= ' . $type . ' size=' . $size);

        switch (strtolower($type)) {
            case 'process_event':
                $this->process_event($output, $size, $interval);
                break;
            case 'offline':
                $this->offline($output, $size);
                break;
            case 'clear':
                $this->clear($output);
                break;
            default:
                $this->clear($output);
                break;
        }
        $cost_time = microtime(true) - $time;
        $output->info('cost ' . $cost_time . ' s');
    }

    /**
     * 处理设备事件 | 加热棒
     * @param Output $output
     * @param int $size
     * @param int $interval
     * @throws \think\Exception
     */
    private function process_event(Output $output, $size = 30, $interval = 30)
    {
        $output->info('process_event start');
        while (true) {
            sleep($interval);
            $page = ['curpage' => 0, 'size' => $size];
            $userDeviceLogic = new UserDeviceLogic();
            $deviceEventLogic = new HeatingRodDeviceEventLogic();
            // 1. 查询所有未处理的加热棒设备事件 分页，按时间从旧到新
            $result = $deviceEventLogic->query(['pro_status' => HeatingRodDeviceEvent::PRO_STATUS_NOT_PROCESS], $page, "id asc");
            if (!$result['status']) {
                $output->error($result['info']);
            }
            $list = $result['info']['list'];
            $now = time();
            $output->info('process count = ' . count($list));
            $allEntity = [];
            foreach ($list as $item) {
                // 2. 遍历所有事件
                $id = $item['id'];
                $did = $item['did'];
                $eventType = $item['event_type'];
                $entity = ['update_time' => $now, 'pro_status' => HeatingRodDeviceEvent::PRO_STATUS_PROCESSED];
                $entity['id'] = $id;

                $content = json_decode($item['event_info'], JSON_OBJECT_AS_ARRAY);
                if ($eventType == 1) {
                    $ret = $this->addTempHis($did, $content, $item, $output);
                    if (!$ret) {
                        $entity['pro_status'] = HeatingRodDeviceEvent::PRO_STATUS_FAILED;
                    }
                    array_push($allEntity, $entity);
                    continue;
                } elseif ($eventType == 0) {
                    //无操作 | 温度数据 过滤掉不推送
                    array_push($allEntity, $entity);
                    continue;
                }

                //最多取50个，一台设备被50个人以上绑定的情况不处理，效率
                $result = $userDeviceLogic->query(['did' => $did], ['curpage' => 0, 'size' => 50]);

                if (ValidateHelper::legalArrayResult($result) && array_key_exists('list', $result['info'])) {
                    $list = $result['info']['list'];
                    // 获取该设备的控制密码
                    $ctrl_pwd = CommandHelper::getCtrlPwd($did, new HeatingRodDeviceLogic());
                    $this->pushEventToUser($output, $ctrl_pwd, $list, $item);
                }
                array_push($allEntity, $entity);
            }
            if (count($allEntity) > 0) {
                $result = (new HeatingRodDeviceEventLogic())->saveAll($allEntity);
                if ($result['status']) {
                    $output->info(' save_all = ' . count($result['info']));
                } else {
                    $output->info(' save_all error = ' . $result['info']);
                }
            }

        }
        $output->info('process_event end');
    }

    /**
     * 记录实时温度
     * @param $did
     * @param $content
     * @param $item
     * @return bool
     * @throws \think\Exception
     */
    private function addTempHis($did, $content, $item, $output = null)
    {
        //实时温度数据
        $temp = 0;
        if (array_key_exists("t", $content)) {
            $temp = intval($content['t']);
        }
        if ($temp <= 0) {
            return false;
        }
        // 检查温度是否高温或低温
        $this->checkTemp($did, $item['create_time'], $temp, $output);

        $result = (new HeatingRodTempHisAction())->add($did, $content, $item);
        if ($result['status']) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 检查温度 | 如果超过限制则报警
     * @param $did
     * @param $time
     * @param $temp
     * @param null $output
     * @throws \think\Exception
     */
    public function checkTemp($did, $time, $temp, $output = null)
    {

        $ctrl_pwd = CommandHelper::getCtrlPwd($did, new HeatingRodDeviceLogic());
        //
        $result = (new UserDeviceLogic())->query(['did' => $did], ['curpage' => 0, 'size' => 50]);
        if ($result['status'] && count($result['info']['list']) > 0) {
            $list = $result['info']['list'];
            foreach ($list as $vo) {
                $uid = $vo['uid'];
                $nickname = $vo['device_nickname'];
                $temp_min = $vo['temp_min'];
                $temp_max = $vo['temp_max'];
                $temp_alert = $vo['temp_alert'];
                $lang = $vo['lang'];
                $extra = json_decode($vo['extra'], JSON_OBJECT_AS_ARRAY);
                if (!is_array($extra) || !array_key_exists("pwd", $extra) || ($extra['pwd'] != 'sunsun123456' && $extra['pwd'] != $ctrl_pwd)) {
                    // 密码不一致就不需要处理
                    continue;
                }
                if (intval($temp_alert) == 1) {
                    if ($temp < $temp_min) {
                        // 如果10分钟前 已经推送过该信息
//                        $eventType = 'c1';
//                        $isPushed = (new PushLogAction())->log($uid, $did, $eventType);
//                        if ($isPushed) {
//                            continue;
//                        }
                        // 温度低温报警
                        $data = [
                            'to_uid' => $uid,
                            'title' => lang('equipment_error_notification', ['nickname' => $nickname], $lang),
                            'content' => lang('equipment_temp_min', ['nickname' => $nickname, 'no' => $did, 'time' => toDatetime($time), 'temp' => toTemperature($temp), 'temp_min' => toTemperature($temp_min)], $lang),
                        ];

                        if ($time > time() - 1800) {
                            $result = CommandHelper::pushUMeng($data);
                            if (!$result['status']) {
                                addLog("device_event/checkTemp", $result, $data, "[error] 温度低温报警", true);
                            }
                        }
                    } elseif ($temp > $temp_max) {
//                        $eventType = 'c2';
//                        $isPushed = (new PushLogAction())->log($uid, $did, $eventType);
//                        if ($isPushed) {
//                            continue;
//                        }
                        // 温度高温报警
                        $data = [
                            'to_uid' => $uid,
                            'title' => lang('equipment_error_notification', ['nickname' => $nickname], $lang),
                            'content' => lang('equipment_temp_max', ['no' => $did, 'nickname' => $nickname, 'time' => toDatetime($time), 'temp' => toTemperature($temp), 'temp_max' => toTemperature($temp_max)], $lang),
                        ];

                        if ($time > time() - 1800) {
                            $result = CommandHelper::pushUMeng($data);
                            if (!$result['status']) {
                                addLog("device_event/checkTemp", $result, $data, "[error] 温度高温报警", true);
                            }
                        }
                    }

                }

            }
        }
    }

    protected function pushEventToUser(Output $output, $ctrl_pwd, $list, $item)
    {
        $time = $item['create_time'];
        $did = $item['did'];
        $eventType = $item['event_type'];
        $output->info('wait pushing count = ' . count($list));
        foreach ($list as $deviceItem) {
            $uid = $deviceItem['uid'];
            $timezone = intval($deviceItem['timezone']);
            $lang = $deviceItem['lang'];
            $extra = json_decode($deviceItem['extra'], JSON_OBJECT_AS_ARRAY);
            if (!is_array($extra) || !array_key_exists("pwd", $extra) || ($extra['pwd'] != 'sunsun123456' && $extra['pwd'] != $ctrl_pwd)) {
                $output->info('did=' . $did . ' password illegal uid=' . $uid);
                // 密码不一致就不需要处理
                continue;
            }
            if (is_array($extra) && array_key_exists('push_cfg', $extra)) {
                $push_cfg = intval($extra['push_cfg']);
                if (intval($push_cfg) == 0) {
                    // 推送开关关闭了，就无需推送
                    continue;
                }
            }
            $content = lang('heating_rod_event_type_' . $eventType, '', $lang);
            $localTime = gmdate('H:i:s', $timezone * 3600 + $time);
            $nickname = $deviceItem['device_nickname'];

            // 如果10分钟前 已经推送过该信息
//            $isPushed = (new PushLogAction())->log($uid, $did, $eventType);
//            if ($isPushed) {
//                $output->info('did=' . $did . ' last 10 min had pushed uid=' . $uid);
//                continue;
//            }
            // 推送消息
            $data = [
                'to_uid' => $uid,
                'title' => lang('device_notify_title', ['nickname' => $nickname, 'device_type' => lang('heating_rod', '', $lang)], $lang),
                'content' => lang('device_notify_content', ['nickname' => $nickname, 'time' => $localTime, 'content' => $content], $lang)
            ];
            CommandHelper::pushUMeng($data);
        }
    }

    private function offline(Output $output, $size = 10)
    {
        $output->info('offline start');
        $result = CommandHelper::offline_notify($size, new HeatingRodDeviceLogic(), 'heating_rod');
        if ($result['status']) {
            $cnt = count($result['info']);
            $output->info('effect ' . $cnt);
        }
        $output->info('offline end');
    }

    private function clear(Output $output)
    {
        $output->highlight('heating_rod clear start');
        //1. tcp接口日志
        $now = time();
        $dataTimestamp = $now - 3 * 3600;
        (new HeatingRodTcpLogAction())->clearExpiredData($dataTimestamp);

        //2. 事件日志
        $dataTimestamp = $now - 10 * 3600;
        (new HeatingRodDeviceEventAction())->clearExpiredData($dataTimestamp);

        $dataTimestamp = $now - 60 * 24 * 3600;
        (new HeatingRodTempHisAction())->clearExpiredData($dataTimestamp);
        $output->highlight('heating_rod clear end');
    }
}